package com.yc.ycrpc;

import com.yc.ycrpc.codec.Decoder;
import com.yc.ycrpc.codec.Encoder;
import com.yc.ycrpc.transport.RequestHandler;
import com.yc.ycrpc.transport.TransportServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;

/**
 * @author yc112
 */
@Slf4j
public class RpcServer {

    private RpcServerConfig config;
    private TransportServer net;
    private Encoder encoder;
    private Decoder decoder;
    private ServiceManager serviceManager;
    private ServiceInvoker serviceInvoker;

    public RpcServer() {
        this(new RpcServerConfig());
    }

    public RpcServer(RpcServerConfig config) {
        this.config = config;

        // net
        this.net = ReflectionUtils.newInstance(config.getTransportClass());
        // 此处还需要调用网络的init的方法
        this.net.init(config.getPort(), this.handler);
        // code
        this.encoder = ReflectionUtils.newInstance(config.getEncoderClass());
        this.decoder = ReflectionUtils.newInstance(config.getDecoderClass());

        //service
        this.serviceManager = new ServiceManager();
        this.serviceInvoker = new ServiceInvoker();
    }

    /**
     * @param interfaceClass 接口Class
     * @param bean 接口具体对象
     */
    public <T> void register(Class<T> interfaceClass, T bean) {
       serviceManager.register(interfaceClass, bean);
    }

    public void start() {
        this.net.start();
    }

    public void stop() {
        this.net.stop();
    }

    private RequestHandler handler = new RequestHandler() {
        @Override
        public void onRequest(InputStream recive, OutputStream toRepon) {
            // 1. 从revice中读取数据
            // 2. 反序列化数据
            // 在协议中定义好的response
            Response response = new Response();
            try {
                // 直接使用io包中转字节数组
                byte[] bytes = IOUtils.readFully(recive, recive.available());
                // 反序列化二进制
                Request request = decoder.decode(bytes, Request.class);
                log.info("get request {}" , request);
                // 通过request找到服务
                ServiceInstance lookup = serviceManager.lookup(request);
                // 有instance 就可以用invoker调用
                Object ret = serviceInvoker.invoker(lookup, request);

                response.setData(ret);
            } catch (Exception e) {
                // 扩大捕获异常，并设置错误信息
                log.warn(e.getMessage(), e);
                response.setCode(1);
                response.setMessage("Rpcserver got error"
                        + e.getClass().getName()
                        + ":" + e.getMessage());
            } finally {
                try{
                    // 将response序列化成二进制数组
                    byte[] outBytes = encoder.encode(response);
                    toRepon.write(outBytes);

                    log.info("response client");
                } catch (IOException e) {
                    log.warn(e.getMessage(), e);
                }
            }

        }
    };
}
